#ifndef __PredefinedControllers_H__
#define __PredefinedControllers_H__


#include "U2PreRequest.h"
#include "U2Common.h"
#include "U2Controller.h"
#include "U2FrameListener.h"


U2EG_NAMESPACE_BEGIN


class TextureUnitState;


//-----------------------------------------------------------------------
// Controller Values
//-----------------------------------------------------------------------
/** Predefined controller value for getting the latest frame time.
*/
class _U2Share FrameTimeControllerValue : public ControllerValue<u2real>, public U2FrameListener
{
protected:
    u2real mFrameTime;
	u2real mTimeFactor;
	u2real mElapsedTime;
	u2real mFrameDelay;

public:
    FrameTimeControllerValue();
    bool frameEnded(const FrameEvent &evt);
    bool frameStarted(const FrameEvent &evt);
    u2real getValue(void) const;
    void setValue(u2real value);
	u2real getTimeFactor(void) const;
	void setTimeFactor(u2real tf);
	u2real getFrameDelay(void) const;
	void setFrameDelay(u2real fd);
	u2real getElapsedTime(void) const;
	void setElapsedTime(u2real elapsedTime);
};

//-----------------------------------------------------------------------
/** Predefined controller value for getting / setting the frame number of a texture layer
*/
class _U2Share TextureFrameControllerValue : public ControllerValue<u2real>
{
protected:
    TextureUnitState* mTextureLayer;

public:
    TextureFrameControllerValue(TextureUnitState* t);

    /** Gets the frame number as a parametric value in the range [0,1]
    */
    u2real getValue(void) const;
    /** Sets the frame number as a parametric value in the range [0,1]; the actual frame number is value * (numFrames-1).
    */
    void setValue(u2real value);

};
//-----------------------------------------------------------------------
/** Predefined controller value for getting / setting a texture coordinate modifications (scales and translates).
    @remarks
        Effects can be applied to the scale or the offset of the u or v coordinates, or both. If separate
        modifications are required to u and v then 2 instances are required to control both independently, or 4
        if you ant separate u and v scales as well as separate u and v offsets.
    @par
        Because of the nature of this value, it can accept values outside the 0..1 parametric range.
*/
class _U2Share TexCoordModifierControllerValue : public ControllerValue<u2real>
{
protected:
    bool mTransU, mTransV;
    bool mScaleU, mScaleV;
    bool mRotate;
    TextureUnitState* mTextureLayer;
public:
    /** Constructor.
        @param
            t TextureUnitState to apply the modification to.
        @param
            translateU If true, the u coordinates will be translated by the modification.
        @param
            translateV If true, the v coordinates will be translated by the modification.
        @param
            scaleU If true, the u coordinates will be scaled by the modification.
        @param
            scaleV If true, the v coordinates will be scaled by the modification.
        @param
            rotate If true, the texture will be rotated by the modification.
    */
    TexCoordModifierControllerValue(TextureUnitState* t, bool translateU = false, bool translateV = false,
        bool scaleU = false, bool scaleV = false, bool rotate = false );

    u2real getValue(void) const;
    void setValue(u2real value);

};

//-----------------------------------------------------------------------
// Controller functions
//-----------------------------------------------------------------------

/** Predefined controller function which just passes through the original source
directly to dest.
*/
class _U2Share PassthroughControllerFunction : public ControllerFunction<u2real>
{
public:
	/** Constructor.
	@param
	sequenceTime The amount of time in seconds it takes to loop through the whole animation sequence.
	@param
	timeOffset The offset in seconds at which to start (default is start at 0)
	*/
	PassthroughControllerFunction(bool deltaInput = false);

	/** Overriden function.
	*/
	u2real calculate(u2real source);
};

/** Predefined controller function for dealing with animation.
*/
class _U2Share AnimationControllerFunction : public ControllerFunction<u2real>
{
protected:
    u2real mSeqTime;
    u2real mTime;
public:
    /** Constructor.
        @param
            sequenceTime The amount of time in seconds it takes to loop through the whole animation sequence.
        @param
            timeOffset The offset in seconds at which to start (default is start at 0)
    */
    AnimationControllerFunction(u2real sequenceTime, u2real timeOffset = 0.0f);

    /** Overridden function.
    */
    u2real calculate(u2real source);

	/** Set the time value manually. */
	void setTime(u2real timeVal);
	/** Set the sequence duration value manually. */
	void setSequenceTime(u2real seqVal);
};

//-----------------------------------------------------------------------
/** Predefined controller function which simply scales an input to an output value.
*/
class _U2Share ScaleControllerFunction : public ControllerFunction<u2real>
{
protected:
    u2real mScale;
public:
    /** Constructor, requires a scale factor.
    @param
        scalefactor The multiplier applied to the input to produce the output.
    @param
        deltaInput If true, signifies that the input will be a delta value such that the function should
         add it to an internal counter before calculating the output.
    */
    ScaleControllerFunction(u2real scalefactor, bool deltaInput);

    /** Overridden method.
    */
    u2real calculate(u2real source);

};

//-----------------------------------------------------------------------
/** Predefined controller function based on a waveform.
@remarks
    A waveform function translates parametric input to parametric output based on a wave. The factors
    affecting the function are:
    - wave type - the shape of the wave
    - base - the base value of the output from the wave
    - frequency - the speed of the wave in cycles per second
    - phase - the offset of the start of the wave, e.g. 0.5 to start half-way through the wave
    - amplitude - scales the output so that instead of lying within [0,1] it lies within [0,1] * amplitude
	- duty cycle - the active width of a PWM signal
@par
    Note that for simplicity of integration with the rest of the controller insfrastructure, the output of
    the wave is parametric i.e. 0..1, rather than the typical wave output of [-1,1]. To compensate for this, the
    traditional output of the wave is scaled by the following function before output:
@par
    output = (waveoutput + 1) * 0.5
@par
    Hence a wave output of -1 becomes 0, a wave ouput of 1 becomes 1, and a wave output of 0 becomes 0.5.
*/
class _U2Share WaveformControllerFunction : public ControllerFunction<u2real>
{
protected:
    WaveformType mWaveType;
    u2real mBase;
    u2real mFrequency;
    u2real mPhase;
    u2real mAmplitude;
	u2real mDutyCycle;

    /** Overridden from ControllerFunction. */
    u2real getAdjustedInput(u2real input);

public:
    /** Default constructor, requires at least a wave type, other parameters can be defaulted unless required.
        @param
            deltaInput If true, signifies that the input will be a delta value such that the function should
            add it to an internal counter before calculating the output.
		@param
			dutyCycle Used in PWM mode to specify the pulse width.
    */
    WaveformControllerFunction(WaveformType wType, u2real base = 0, u2real frequency = 1, u2real phase = 0, u2real amplitude = 1, bool deltaInput = true, u2real dutyCycle = 0.5);

    /** Overridden function.
    */
    u2real calculate(u2real source);

};


U2EG_NAMESPACE_END


#endif
